﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Web;

using Refix.Core.Repository;
using Refix.Repository.ViewModels;
using Refix.Core;

using Configuration = Refix.Core.Configuration;

namespace Refix.Repository.Models
{
    public class RepositoryModel
    {
        private readonly VersionNumberComparer _versionNumberComparer = new VersionNumberComparer();
        private readonly LocalRepository _localRepository = new LocalRepository();

        public List<SummaryEntry> GetSummary()
        {
            var results = new List<SummaryEntry>();
            var directoryInfo = new DirectoryInfo(Configuration.LocalRepository);
            string root = Path.Combine(Configuration.LocalRepository, "root");
            RecurseDirectory(directoryInfo, root, results);
            return results;
        }

        private void RecurseDirectory(DirectoryInfo directoryInfo, string root,  List<SummaryEntry> results)
        {
            foreach (var directory in directoryInfo.GetDirectories())
            {
                if (directory.GetFiles("versions.xml").Count() != 0)
                {
                    string componentName =
                        PathUtilities.MakeRelativePath(root, directory.FullName).Replace("\\", ".");
                    Component component = _localRepository.GetComponent(componentName);
                    if (component != null)
                    {
                        results.Add(new SummaryEntry
                        {
                            Component = componentName,
                            VersionCount = component.Versions.Count,
                            MaximumVersion = component.Versions.OrderBy(v => v.Number, _versionNumberComparer).Last().Number,
                            LocalRevision = component.LocalRevision,
                            RemoteRevision = component.RemoteRevision
                        });
                    }
                }
                RecurseDirectory(directory, root, results);
            }
        }

        public int GetRevision(string assemblyName)
        {
            return _localRepository.GetComponentLocalRevision(assemblyName);
        }

        public byte[] GetZipFile(string component, string version)
        {
            return _localRepository.GetComponentVersionZipFile(component, version);
        }

        public IEnumerable<PendingUpload> GetPendingUploads()
        {
            string uploadFolder = GetUploadFolder();
            var info = new DirectoryInfo(uploadFolder);
            var results = new List<PendingUpload>();
            foreach (var fileInfo in info.GetFiles("*.zip"))
            {
                var upload = new PendingUpload();
                upload.Identifier = new Guid(Path.GetFileNameWithoutExtension(fileInfo.Name));
                using (var textFile = File.OpenText(Path.ChangeExtension(fileInfo.FullName, "txt")))
                {
                    upload.ComponentName = textFile.ReadLine();
                    upload.Version = textFile.ReadLine();
                    upload.Uploader = textFile.ReadLine();
                }
                results.Add(upload);
            }
            return results;
        }

        public byte[] GetUploadedZipData(Guid identifier)
        {
            string uploadFolder = GetUploadFolder();
            string fileNameGuid = identifier.ToString("N");
            string fileName = Path.Combine(uploadFolder,
                                           fileNameGuid + ".zip");
            return File.ReadAllBytes(fileName);
        }

        public void DeleteUploadedFiles(Guid identifier)
        {
            string uploadFolder = GetUploadFolder();
            string fileNameGuid = identifier.ToString("N");
            string fileName = Path.Combine(uploadFolder,
                                           fileNameGuid + ".zip");
            File.Delete(fileName);
            fileName = Path.ChangeExtension(fileName, ".txt");
            File.Delete(fileName);
        }

        public void SendEmail(string subject, string body, Guid identifier)
        {
            bool enabled;
            bool.TryParse(ConfigurationManager.AppSettings["Refix.Email.Enabled"] ?? "false", out enabled);
            if (!enabled)
            {
                return;
            }
            string uploadFolder = GetUploadFolder();
            string fileNameGuid = identifier.ToString("N");
            string fileName = Path.Combine(uploadFolder,
                                           fileNameGuid + ".zip");
            string component;
            string version;
            string email;
            using (var textFile = File.OpenText(Path.ChangeExtension(fileName, "txt")))
            {
                component = textFile.ReadLine();
                version = textFile.ReadLine();
                email = textFile.ReadLine();
            }
            subject = string.Format(subject, component, version);
            body = string.Format(body, component, version);
            var message = new MailMessage(ConfigurationManager.AppSettings["Refix.Email.FromAddress"], email,
                                          subject, body);
            int port;
            if (!int.TryParse(ConfigurationManager.AppSettings["Refix.Email.Port"] ?? "25", out port))
            {
                port = 25;
            }
            var smtpClient = new SmtpClient(ConfigurationManager.AppSettings["Refix.Email.Host"], port);
            smtpClient.Send(message);
        }

        public void ProcessZipData(Guid identifier)
        {
            string uploadFolder = GetUploadFolder();
            string fileNameGuid = identifier.ToString("N");
            string fileName = Path.Combine(uploadFolder,
                                           fileNameGuid + ".zip");
            string component;
            using (var textFile = File.OpenText(Path.ChangeExtension(fileName, "txt")))
            {
                component = textFile.ReadLine();
            }
            RepositoryUtilities.MergeZipFile(Configuration.LocalRepository, PathUtilities.GetComponentPath(Configuration.LocalRepository, component), fileName, MergeDirection.Download);
        }

        public void ProcessZipData(byte[] zip, string component, string version, string email)
        {
            if (!version.IsNullOrEmpty() && _localRepository.GetComponentVersion(component, version, false) != null)
            {
                throw new HttpException((int)HttpStatusCode.Conflict, "Conflict");
            }
            string uploadFolder = GetUploadFolder();
            string fileNameGuid = Guid.NewGuid().ToString("N");
            string fileName = Path.Combine(uploadFolder,
                                           fileNameGuid + ".zip");
            File.WriteAllBytes(fileName, zip);
            if (ConfigurationManager.AppSettings["Refix.Upload.Mode"] == "Direct")
            {
                RepositoryUtilities.MergeZipFile(Configuration.LocalRepository, PathUtilities.GetComponentPath(Configuration.LocalRepository, component), fileName, MergeDirection.Download);
                File.Delete(fileName);
            }
            else
            {
                string propertiesFileName = Path.Combine(uploadFolder,
                                                         fileNameGuid + ".txt");
                using (StreamWriter writer = File.CreateText(propertiesFileName))
                {
                    writer.WriteLine(component);
                    writer.WriteLine(version);
                    writer.WriteLine(email);
                }
            }
        }

        private string GetUploadFolder()
        {
            string uploadFolder = ConfigurationManager.AppSettings["Refix.Upload.Folder"];
            if (uploadFolder.StartsWith("~"))
            {
                uploadFolder = HttpContext.Current.Server.MapPath(uploadFolder);
            }
            return uploadFolder;
        }
    }
}